package com.css.fxfzfxqh.util;

import lombok.extern.slf4j.Slf4j;
import org.gdal.gdal.Band;
import org.gdal.gdal.Dataset;
import org.gdal.gdal.gdal;
import org.gdal.gdalconst.gdalconstConstants;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Author: zyt
 * @CreateTime: 2023/5/4
 * @Description: tif文件解析
 */
@Slf4j
public class TifAnalyticUtil {


    /**
     * 解析tif文件
     *
     * @param tif .tif文件的真实地址
     * @return
     */
    public static ParsingResult analytic(String tif) {
        log.info("进行tif文件解析 >> {}", tif);
        //校验是否为2000坐标系
        if (!(checkCGCS2000Tif(tif))) {
            log.info(new Date() + "-----------校验失败.请上传正确的CGCS2000坐标系数据.tif文件.");
            return ParsingResult.tifData("请上传正确的CGCS2000坐标系数据.tif文件", null,0);
        }
        int dataLength = -1;//数据长度
        String checkResult = null;//校验结果
        //获取tif文件全部数据长度--zyt
        int count = getDataLengthByTIF(tif);
        if(count>0){
            //解析成功
        }else{
            return ParsingResult.tifData("解析失败tif文件中没有数据", null,0);
        }
        ArrayList<List<Object>> lists = new ArrayList<>();
        //解析tif文件矢量化数据--所有栅格值各1条数据
        //lists = getTifDataList(tif);
        log.info("tif文件解析成功 >> {}", tif);
        return ParsingResult.tifData("ok", lists, count);
    }

    //校验Tif文件是否为2000坐标系
    public static boolean checkCGCS2000Tif(String path) {
        String name = "";
        gdal.AllRegister();
        Dataset dataset = gdal.Open(path, gdalconstConstants.GA_ReadOnly);
        if (dataset == null) return false;
        name = dataset.GetProjection();//获取地理信息
        dataset.delete();
        gdal.GDALDestroyDriverManager();
        if (name.indexOf("CGCS2000") != -1 || name.indexOf("cgcs2000") != -1 || name.indexOf("Geodetic_Coordinate_System_2000") != -1 ||
                name.indexOf("Geodetic Coordinate System 2000") != -1) return true;

        return false;
    }

    //获取tif文件全部数据长度--zyt
    public static int getDataLengthByTIF(String tifFileName) {
        gdal.AllRegister();

        Dataset dataset = gdal.Open(tifFileName, gdalconstConstants.GA_ReadOnly);
        if (dataset == null) return -1;

        Band band = dataset.GetRasterBand(1);

        int xSize = dataset.getRasterXSize();
        int ySize = dataset.getRasterYSize();

        //GeoTransform 的含义：
        //六参数信息
        double[] geoTransform = dataset.GetGeoTransform();//获取仿射矩阵，含有 6 个元素的元组
        //影像左上角投影坐标
        double[] luCoordinate = new double[2];
        double lon = geoTransform[0];//影像左上角横坐标：对应经度
        double lat = geoTransform[3];//影像左上角纵坐标：对应纬度
        //判断经纬度值是否正常
        if(lon<0 || lon>180 || lat<0 || lat>180){
            return 0;
        }

        int count = 0;
        int buf[] = new int[xSize];
        for(int i = 0; i < ySize; i++) {
            band.ReadRaster(0, i, xSize, 1, buf);
            for(int j = 0; j < xSize; j++) {
                /*//坡度范围：最小值0，最大值90，无数据值255
                if(buf[j] >= 0 && buf[j] <= 90) {
                    count++;
                }*/
                count++;
            }
        }
        dataset.delete();
        gdal.GDALDestroyDriverManager();

        return count;
    }

    //获取tif文件全部数据值列表
    public List<Object> getAllValueListByTIF(String tifFileName) {
        List<Object> result = new ArrayList<Object>();
        List<Integer> valueList = new ArrayList<Integer>();//栅格数值列表
        List<Integer> countList = new ArrayList<Integer>();//计数列表
        gdal.AllRegister();

        Dataset dataset = gdal.Open(tifFileName, gdalconstConstants.GA_ReadOnly);
        if (dataset == null) return null;

        Band band = dataset.GetRasterBand(1);

        int xSize = dataset.getRasterXSize();
        int ySize = dataset.getRasterYSize();

        int buf[] = new int[xSize];
        for(int i = 0; i < ySize; i++) {
            band.ReadRaster(0, i, xSize, 1, buf);
            for(int j = 0; j < xSize; j++) {
                //数值校验
                /*if(buf[j] >= 0 && buf[j] <= 90) {
                    //坡度范围：最小值0，最大值90，无数据值255
                }else{
                    continue;
                }*/
                int index = valueList.indexOf(buf[j]);
                if(index==-1){
                    valueList.add(buf[j]);
                    countList.add(1);
                }else{
                    int count = countList.get(index);
                    countList.set(index,count+1);
                }
            }
        }
        dataset.delete();
        gdal.GDALDestroyDriverManager();

        result.add(valueList);
        result.add(countList);

        return result;
    }

    //获取tif文件数据值
    public String getValueByTIF(String tifFileName) {
        gdal.AllRegister();

        Dataset dataset = gdal.Open(tifFileName, gdalconstConstants.GA_ReadOnly);
        if (dataset == null) return null;

        Band band = dataset.GetRasterBand(1);

        int xSize = dataset.getRasterXSize();
        int ySize = dataset.getRasterYSize();

        StringBuilder sb = new StringBuilder();
        int buf[] = new int[xSize];
        for(int i = 0; i < ySize; i++) {
            band.ReadRaster(0, i, xSize, 1, buf);
            for(int j = 0; j < xSize; j++) {
                //数值校验
                /*if(buf[j] >= 0 && buf[j] <= 90) {
                    //坡度范围：最小值0，最大值90，无数据值255
                }else{
                    continue;
                }*/
                sb.append(buf[j] + "|");
            }
        }
        String gridDataStr = sb.toString();
        gridDataStr = gridDataStr.substring(0, gridDataStr.length() - 1);
        dataset.delete();
        gdal.GDALDestroyDriverManager();

        return gridDataStr;
    }

    //获取tif文件网格矢量数据
    public String getRectsByTIF(String tifFileName) {
        gdal.AllRegister();

        Dataset dataset = gdal.Open(tifFileName, gdalconstConstants.GA_ReadOnly);
        if (dataset == null) return null;
        String projection = dataset.GetProjection();//投影
        Band band = dataset.GetRasterBand(1);//选择要读取的波段数，bandNum 从 1 开始

        int xSize = dataset.getRasterXSize();//获取宽度，数组第二维，左右方向元素长度，代表经度范围
        int ySize = dataset.getRasterYSize();//获取高度，数组第一维，上下方向元素长度，代表纬度范围

        //GeoTransform 的含义：
        //六参数信息
        double[] geoTransform = dataset.GetGeoTransform();//获取仿射矩阵，含有 6 个元素的元组
        //影像左上角投影坐标
        double[] luCoordinate = new double[2];
        luCoordinate[0] = geoTransform[0];//影像左上角横坐标：对应经度
        luCoordinate[1] = geoTransform[3];//影像左上角纵坐标：对应纬度
        //通常水平和垂直分辨率相等
        //遥感图像的垂直空间分辨率(经度间隔)
        double fblLon = geoTransform[1];
        //遥感图像的水平空间分辨率(纬度间隔)：
        double fblLat = geoTransform[5];
        //如果遥感影像方向没有发生旋转，即上北下南，则 geoTransA 与 geoTransB 为 0
        double geoTransA = geoTransform[2];
        double geoTransB = geoTransform[4];

        /*计算图像地理坐标：
        若图像中某一点的行数和列数分别为 row 和 column，则该点的地理坐标为：
        经度：xGeo = geoTransform[0] + row * geoTransform[1] + column * geoTransform[2]
        纬度：yGeo = geoTransform[3] + row * geoTransform[4] + column * geoTransform[5]
        */

        int count = 0;
        int buf[] = new int[xSize];
        String coordinate = "";
        StringBuilder sb = new StringBuilder();
        sb.append("MUTLTIPOLYGON (");
        for(int i = 0; i < ySize; i++) {
            band.ReadRaster(0, i, xSize, 1, buf);
            for(int j = 0; j < xSize; j++) {
                //数值校验
                /*if(buf[j] >= 0 && buf[j] <= 90) {
                    //坡度范围：最小值0，最大值90，无数据值255
                }else{
                    continue;
                }*/
                double luLon = geoTransform[0] + j * geoTransform[1] + i * geoTransform[2];
                double luLat = geoTransform[3] + j * geoTransform[4] + i * geoTransform[5];

                double ruLon = geoTransform[0] + (j + 1) * geoTransform[1] + i * geoTransform[2];
                double ruLat = geoTransform[3] + (j + 1) * geoTransform[4] + i * geoTransform[5];

                double rbLon = geoTransform[0] + (j + 1) * geoTransform[1] + (i + 1) * geoTransform[2];
                double rbLat = geoTransform[3] + (j + 1) * geoTransform[4] + (i + 1) * geoTransform[5];

                double lbLon = geoTransform[0] + j * geoTransform[1] + (i + 1) * geoTransform[2];
                double lbLat = geoTransform[3] + j * geoTransform[4] + (i + 1) * geoTransform[5];

                //coordinate = luLon + " " + luLat + "," + ruLon + " " + ruLat + "," + rbLon + " " + rbLat + "," + lbLon + " " + lbLat + "|";
                if(count>0){
                    coordinate = ", ";
                }else{
                    coordinate = "";
                }
                coordinate += "((" + luLon + " " + luLat + ", " + ruLon + " " + ruLat + ", " + rbLon + " " + rbLat + ", " + lbLon + " " + lbLat + ", " + luLon + " " + luLat + "))";
                sb.append(coordinate);
                count++;
                if(count%5000==0){
                    System.out.println("----count: " + count);
                }
            }
        }
        System.out.println("----count: " + count);
        sb.append(")");
        coordinate = sb.toString();
        //coordinate = coordinate.substring(0, coordinate.length() - 1);
        dataset.delete();
        gdal.GDALDestroyDriverManager();
        return coordinate;
    }

    //解析tif文件矢量化数据--所有栅格值各1条数据
    private static ArrayList<List<Object>> getTifDataList(String filePath) {
        ArrayList<List<Object>> lists = new ArrayList<>();
        System.out.println(new Date()+"-------------------1.开始readTifFile");
        //gdal读取tif文件
        gdal.AllRegister();
        Dataset dataset = gdal.Open(filePath, gdalconstConstants.GA_ReadOnly);
        if (dataset == null) return null;
        String projection = dataset.GetProjection();//投影
        Band band = dataset.GetRasterBand(1);//选择要读取的波段数，bandNum 从 1 开始

        int xSize = dataset.getRasterXSize();//获取宽度，数组第二维，左右方向元素长度，代表经度范围
        int ySize = dataset.getRasterYSize();//获取高度，数组第一维，上下方向元素长度，代表纬度范围

        //GeoTransform 的含义：
        //六参数信息
        double[] geoTransform = dataset.GetGeoTransform();//获取仿射矩阵，含有 6 个元素的元组
        //影像左上角投影坐标
        double[] luCoordinate = new double[2];
        luCoordinate[0] = geoTransform[0];//影像左上角横坐标：对应经度
        luCoordinate[1] = geoTransform[3];//影像左上角纵坐标：对应纬度
        //通常水平和垂直分辨率相等
        //遥感图像的垂直空间分辨率(经度间隔)
        double fblLon = geoTransform[1];
        //遥感图像的水平空间分辨率(纬度间隔)：
        double fblLat = geoTransform[5];
        //如果遥感影像方向没有发生旋转，即上北下南，则 geoTransA 与 geoTransB 为 0
        double geoTransA = geoTransform[2];
        double geoTransB = geoTransform[4];

        /*计算图像地理坐标：
        若图像中某一点的行数和列数分别为 row 和 column，则该点的地理坐标为：
        经度：xGeo = geoTransform[0] + row * geoTransform[1] + column * geoTransform[2]
        纬度：yGeo = geoTransform[3] + row * geoTransform[4] + column * geoTransform[5]
        */

        int buf[] = new int[xSize];
        String coordinate = "";
        for(int i = 0; i < ySize; i++) {
            band.ReadRaster(0, i, xSize, 1, buf);
            for(int j = 0; j < xSize; j++) {
                /*//数值校验
                if(buf[j] >= 0 && buf[j] <= 90) {
                    //坡度范围：最小值0，最大值90，无数据值255
                }else{
                    continue;
                }*/
                double luLon = geoTransform[0] + j * geoTransform[1] + i * geoTransform[2];
                double luLat = geoTransform[3] + j * geoTransform[4] + i * geoTransform[5];

                double ruLon = geoTransform[0] + (j + 1) * geoTransform[1] + i * geoTransform[2];
                double ruLat = geoTransform[3] + (j + 1) * geoTransform[4] + i * geoTransform[5];

                double rbLon = geoTransform[0] + (j + 1) * geoTransform[1] + (i + 1) * geoTransform[2];
                double rbLat = geoTransform[3] + (j + 1) * geoTransform[4] + (i + 1) * geoTransform[5];

                double lbLon = geoTransform[0] + j * geoTransform[1] + (i + 1) * geoTransform[2];
                double lbLat = geoTransform[3] + j * geoTransform[4] + (i + 1) * geoTransform[5];

                coordinate = luLon + " " + luLat + "," + ruLon + " " + ruLat + "," + rbLon + " " + rbLat + "," + lbLon + " " + lbLat;
                coordinate += "," + luLon + " " + luLat;//与第一个点闭合
                //获取tif文件数据值
                int number = buf[j];
                //获取tif文件网格矢量数据
                String geo = "POLYGON (("+coordinate+"))";
                //空间数据
                //String geom = "ST_GeometryFromText('" + geo + "',4490)";
                List<Object> attributes = new ArrayList<>();
                attributes.add(geo);//矢量数据
                attributes.add(number);//栅格数据值
                lists.add(attributes);
            }
        }
        dataset.delete();
        gdal.GDALDestroyDriverManager();
        System.out.println(new Date()+"-------------------2.结束readTifFile");

        return lists;
    }
}
